#include <WiFi.h>
#include <HTTPClient.h>
#include <driver/i2s.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>

// WiFi 配置
const char* ssid = "你的无线ssid";
const char* password = "你的wifi秘码";

// Azure TTS 配置
const char* azure_key = "你的azure speech的key";
const char* azure_region = "你的azure speech的region";

// I2S引脚定义
#define I2S_BCLK 5
#define I2S_LRC 6
#define I2S_DOUT 17

#define I2S_NUM         I2S_NUM_0
#define I2S_SAMPLE_RATE 16000
#define I2S_BITS_PER_SAMPLE I2S_BITS_PER_SAMPLE_16BIT

#define PCM_SAMPLE_SIZE 2 // 16bit

#define AUDIO_QUEUE_SIZE 8

QueueHandle_t audioQueue;

// I2S初始化
void setupI2S() {
    i2s_config_t i2s_config = {
        .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
        .sample_rate = I2S_SAMPLE_RATE,
        .bits_per_sample = I2S_BITS_PER_SAMPLE,
        .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
        .communication_format = I2S_COMM_FORMAT_I2S,
        .intr_alloc_flags = 0,
        .dma_buf_count = 8,
        .dma_buf_len = 512,
        .use_apll = false,
        .tx_desc_auto_clear = true,
        .fixed_mclk = 0
    };
    i2s_pin_config_t pin_config = {
        .bck_io_num = I2S_BCLK,
        .ws_io_num = I2S_LRC,
        .data_out_num = I2S_DOUT,
        .data_in_num = -1
    };
    i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
    i2s_set_pin(I2S_NUM, &pin_config);
}

// 播放任务
void playTask(void* param) {
    std::vector<uint8_t>* playBuffer;
    while (1) {
        if (xQueueReceive(audioQueue, &playBuffer, portMAX_DELAY) == pdTRUE) {
            if (playBuffer && !playBuffer->empty()) {
                size_t bytes_written = 0;
                i2s_write(I2S_NUM, playBuffer->data(), playBuffer->size(), &bytes_written, portMAX_DELAY);
            }
            delete playBuffer; // 用完释放
        }
    }
}

// 串口输入
String getInputText() {
    Serial.println("请输入要朗读的内容：");
    String input = "";
    while (input.length() == 0) {
        if (Serial.available()) {
            input = Serial.readStringUntil('\n');
            input.trim();
        }
        delay(10);
    }
    return input;
}

// TTS请求和chunk推送到队列
void ttsAndPlay(const String& text) {
    String url = "https://" + String(azure_region) + ".tts.speech.microsoft.com/cognitiveservices/v1";
    HTTPClient http;
    http.begin(url);

    http.addHeader("Ocp-Apim-Subscription-Key", azure_key);
    http.addHeader("Content-Type", "application/ssml+xml");
    http.addHeader("X-Microsoft-OutputFormat", "raw-16khz-16bit-mono-pcm");
    http.addHeader("User-Agent", "ESP32TTS");

    String ssml = "<speak version='1.0' xml:lang='zh-CN'>"
                "<voice name='zh-CN-XiaoxiaoMultilingualNeural'>"
                "<lang xml:lang='zh-CN'><prosody rate='+20.00%'>"
                + text +
                "</prosody></lang></voice></speak>";

    int httpCode = http.POST(ssml);
    if (httpCode == HTTP_CODE_OK) {
        WiFiClient* stream = http.getStreamPtr();
        while (stream->connected()) {
            // 1. 读取 chunk size
            String chunkSizeStr = stream->readStringUntil('\n');
            chunkSizeStr.trim();
            if (chunkSizeStr.length() == 0) continue;
            int chunkSize = (int) strtol(chunkSizeStr.c_str(), NULL, 16);
            if (chunkSize == 0) break;

            // 2. 读取 chunk data
            std::vector<uint8_t>* chunkData = new std::vector<uint8_t>(chunkSize);
            size_t totalRead = 0;
            unsigned long startMillis = millis();
            while (totalRead < chunkSize) {
                int bytesRead = stream->read(chunkData->data() + totalRead, chunkSize - totalRead);
                if (bytesRead > 0) {
                    totalRead += bytesRead;
                    startMillis = millis();
                } else {
                    if (millis() - startMillis > 2000) {
                        Serial.println("Chunk read timeout!");
                        break;
                    }
                    delay(1);
                }
            }
            stream->readStringUntil('\n'); // 跳过 chunk 结束的 \r\n

            // 3. 直接丢到队列
            xQueueSend(audioQueue, &chunkData, portMAX_DELAY);
        }
        Serial.println("朗读完成！");
    } else {
        Serial.printf("TTS请求失败: %d\n", httpCode);
    }
    http.end();
}

void setup() {
    Serial.begin(115200);
    WiFi.begin(ssid, password);
    Serial.print("WiFi连接中...");
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("连接成功！");
    setupI2S();

    audioQueue = xQueueCreate(AUDIO_QUEUE_SIZE, sizeof(std::vector<uint8_t>*));
    xTaskCreatePinnedToCore(playTask, "playTask", 4096, NULL, 1, NULL, 1); // 1号核
}

void loop() {
    String text = getInputText();
    ttsAndPlay(text);
}
